#include "include\\Common.fxh"

/*
% Point Light.
date: 05/29/12
*/
/*****************Un-Twealables**********************************/
//after colon is a semantic usefull later for knowing what variables this shader has
float4x4 WorldViewProjection : WORLDVIEWPROJECTION <string UIWidget="None";>;// < = annoation only for FXCOMPOSER 
float4x4 WorldInverseTranspose : WORLDINVERSETRANSPOSE <string UIWidget="None";>;
float4x4 World:WORLD <string UIWidget = "None";>;
float4x4 ViewInverse:VIEWINVERSE <string UIWidget = "None";>;

#define NUM_LIGHTS 4
const int NumLights < string UWidget = "None"; > = NUM_LIGHTS;

/****************Tweakables************************************/
/**Texture**/
texture ColorTexture : COLOR 
< string ResouceName = "default_color.dds";
  string UIName = "Color Texture";
  string ResourceType = "2D";>;
  
/**Ambient**/
float4 AmbientColor : COLOR
< string UIName = "Ambient Light";
  string UIWidget = "Color";
> = {1.0f,1.0f,1.0f,1.0f};

/**Light**/
POINT_LIGHT pointLight;

/**FOG**/
float3 FogColor
< string UIName = "Fog Color";
  string UIWidget = "Color";
> = {0.5f,0.5f,0.5f};
float FogStart = {20.0f};
float FogEnd = {40.0f};
bool FogEnabled = true;

/**PHONG**/
float4 SpecularColor : SPECULAR < 
	string UIName = "Specular Color";
	string UIWidget = "Color";
> = {1.0f,1.0f,1.0f,1.0f};

float SpecularPower : SPECULARPOWER <
	string UIName = "Specular Power";
	string UIWidget = "slider";
	float UIMin = 1.0;
	float UIMax = 128.0;
	float UIStep = 1.0;
> = {8.0f};

/**DISPLACEMENT**/
texture DisplacementTexture
<
	string ResourceName = "default_bump_normal.dds";
	string ResourceType = "2D";
>;
sampler DisplacementSampler = sampler_state
{
	Texture = <DisplacementTexture>; //the texture it will be grabbing pixel date from
	Magfilter = LINEAR;		  //zoom in - does linear interpelation
	Minfilter = LINEAR;		  //zoom out
	Mipfilter = LINEAR;
	AddressU = Wrap;		  //wrap or clamp
	AddressV = Wrap;		  //uv values or 0 to 1 oustide that they must either be wrapped(round up to the next) or clamped(made to fit in 0to1)>; //the texture it will be grabbing pixel date from
};
float DisplacementScale
<
	string UIName = "Displacement Scale";
	string UIWidget = "slider";
	float UIMin = 0.0;
	float UIMax = 10.0;
	float UIStep = 0.1;
> = {0.0f};

/***************Un-Tweakable************************************/
sampler2D ColorSampler = sampler_state
{	
	Texture = <ColorTexture>; //the texture it will be grabbing pixel date from
	Magfilter = LINEAR;		  //zoom in - does linear interpelation
	Minfilter = LINEAR;		  //zoom out
	Mipfilter = LINEAR;
	AddressU = Wrap;		  //wrap or clamp
	AddressV = Wrap;		  //uv values or 0 to 1 oustide that they must either be wrapped(round up to the next) or clamped(made to fit in 0to1)
};

/*****************Data Structures****************************/
struct VS_INPUT
{
	float4 ObjectPosition		: POSITION0;
	float2 TextureCoordinate 	: TEXCOORD0;
	float4 Normal				: NORMAL0;
};

struct VS_OUTPUT
{
	float4 ScreenPosition	: POSITION0;
	float2 TextureCoordinate: TEXCOORD0;
	float3 Normal 			: TEXCOORD1;	//no noraml symantic for outup of texture shader...not important simply storing a 4 float
	float  FogAmount 		: TEXCOORD2;
	float4 ViewDirection	: TEXCOORD3; //from the surface to the camera
	float4 LightDirection 	: TEXCOORD4;
};

struct PS_OUTPUT
{
	float4 Color:COLOR0;
};

/*****************Vertex Shader*****************************/
VS_OUTPUT vertex_shader(VS_INPUT IN)
{
	VS_OUTPUT OUT = (VS_OUTPUT)0; //memset clear garbage
	float2 textureCoordinate = get_corrected_texture_coordinate(IN.TextureCoordinate);
	
	float4 objectPosition;
	if(DisplacementScale > 0.0f)
	{
		DISPLACEMENT_MAP_DATA displacementMapData;
		displacementMapData.Position = IN.ObjectPosition;
		displacementMapData.Normal = IN.Normal;
		displacementMapData.TextureCoordinate = float4(textureCoordinate, 0.0f,0.0f);
		displacementMapData.Scale = DisplacementScale;
		objectPosition = get_displaced_position(displacementMapData, DisplacementSampler);
	}
	else
	{
		objectPosition = IN.ObjectPosition;
	}
	
	OUT.ScreenPosition = mul(IN.ObjectPosition, WorldViewProjection);
	OUT.TextureCoordinate = get_corrected_texture_coordinate(IN.TextureCoordinate);
	OUT.Normal = normalize(mul(IN.Normal, WorldInverseTranspose)); //place in the correct coordinate space
	float4 worldPosition = mul(IN.ObjectPosition,World);
	float3 eyePosition = ViewInverse[3].xyz;
	
	OUT.LightDirection = get_light_data(pointLight.Position, worldPosition, pointLight.LightRadius);
	
	OUT.FogAmount = get_fog_amount(eyePosition, worldPosition, FogStart, FogEnd);
	return OUT;
}

/*****************Pixel Shader*******************************/
PS_OUTPUT pixel_shader(VS_OUTPUT IN)
{
	PS_OUTPUT OUT = (PS_OUTPUT)0;
	
	float3 normal = normalize(IN.Normal);
	float3 viewDirection = normalize(IN.ViewDirection);
	float4 color = tex2D(ColorSampler, IN.TextureCoordinate);
	float4 ambient = get_color_contribution(AmbientColor, color);
	
	LIGHT_CONTRIB_DATA lightContribData;
	lightContribData.Color = color;
	lightContribData.Normal = normal;
	lightContribData.ViewDirection = viewDirection;
	lightContribData.SpecularColor = SpecularColor;
	lightContribData.SpecularPower = SpecularPower;
	lightContribData.LightDirection = IN.LightDirection;
	lightContribData.LightColor = pointLight.Color;
	float4 light_contribution = get_light_contribution(lightContribData);

	OUT.Color = ambient + light_contribution;
	
	if(FogEnabled)
	{
		OUT.Color.rgb = apply_fog(FogColor, OUT.Color, IN.FogAmount);
	}
	return OUT;
}

/****************Techniques**********************************/
technique main
{
	pass p0 
	{
		VertexShader = compile vs_3_0 vertex_shader();
		PixelShader = compile ps_3_0 pixel_shader();
	}
}
